import { CheckCircleOutlined, InboxOutlined, PaperClipOutlined, PlusOutlined } from '@ant-design/icons';
import { message, Upload, UploadFile, Image, Button, Progress, UploadProps, Checkbox, Result } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import { getOss, getFileAddress, saveSuccessFileName, uploadSingleFile, importImages } from 'apis/upload';
import BMF from 'browser-md5-file';
import { nanoid } from 'nanoid';

function BatchUploadComponent(props): JSX.Element {
    const { closeDrawer, onAddNewData } = props;
    const { Dragger } = Upload;
    const [fileList, setFileList] = useState<UploadFile[]>([]);
    const filesRef = useRef<UploadFile[]>();
    const [filesProgress, setFilesProgress] = useState<{ fileName: string; progress: number; uid: string; }[]>([]);
    const progressRef = useRef<{ fileName: string; progress: number; uid: string; }[]>();
    const [imgList, setImgList] = useState<{ name: string; src: string; isChecked: boolean; uid: string, folderName?: string; }[]>([]);
    const [selectedCount, setSelectedCount] = useState<number>(0);
    const [indeterminate, setIndeterminate] = useState<boolean>();
    const [selectedAll, setSelectedAll] = useState<boolean>();
    const [importSuccess, setImportSuccess] = useState(false);
    let client;
    const bmf = new BMF();

    useEffect(() => {
        filesRef.current = fileList;
    }, [fileList]);

    useEffect(() => {
        progressRef.current = filesProgress;
    }, [filesProgress]);

    async function saveFileName(file: File, md5: string): Promise<void> {
        await saveSuccessFileName({
            fileMd5: md5,
            fileName: file.name
        })
    }

    function getFileName(name: string): string {
        const imgTypes = ['png', 'jpg', 'jpeg', 'bmp'];//.rar,.zip,.jpg,.png,.jpeg,.bmp
        const strArr = name.split('/');
        const fileName = strArr[strArr.length - 1];
        const typeArr = fileName.split('.');
        if (typeArr && imgTypes.includes(typeArr[typeArr.length - 1])) {
            return fileName;
        } else {
            return '';
        }
    }

    function isMacOSX(name: string): boolean {
        const strArr = name.split('/');
        return strArr[2] === '__MACOSX';
    }

    function getFolderName(name: string): string {
        const strArr = name.split('.');
        return strArr[0];
    }

    function addImages(arr: { name: string; url: string; }[], file): void {
        const images: { name: string; src: string; uid: string; isChecked: boolean; folderName: string }[] = [];
        arr.forEach(v => {
            const fileName = getFileName(v.name);
            const valid = isMacOSX(v.name)
            if (fileName && !valid) {
                images.push({
                    name: fileName,
                    src: v.url,
                    isChecked: true,
                    uid: nanoid(),
                    folderName: file.type === 'application/zip' ? getFolderName(file.name) : getFolderName(fileName),
                });
            }

        })
        const list = [...imgList, ...images];
        const selectedNum = list.filter(v => v.isChecked).length;
        setImgList(list);
        setSelectedAll(list.every(v => v.isChecked));
        setSelectedCount(selectedNum);
        setIndeterminate(!!(selectedNum > 0 && selectedNum < list.length));
    }

    function validFileType(type:string): boolean {
        const accepts = ['application/zip','image/png','image/jpg','image/jpeg','image/bmp'];
        return accepts.includes(type);
    }

    function handleUploadFile(file): void {
        if (!validFileType(file.type)) {
            message.warning('仅支持上传zip/png/jpg/jpeg/bmp格式的文件')
            return;
        }
        const currentFiles = [...fileList, file];
        setFileList(val => [...val, file]);
        filesRef.current = currentFiles;
        const arr = [...filesProgress, { fileName: file.name, progress: 0, uid: file.uid }];
        setFilesProgress(val => [...val, { fileName: file.name, progress: 0, uid: file.uid }]);
        progressRef.current = arr;
        if (file.type === 'application/zip') {
            bmf.md5(file, async (err, md5) => {
                const res = await getOss({
                    fileMd5: md5,
                })
                //existFlag为true说明此文件已经上传过了，直接获取下面的文件list即可
                //为false，说明没上传过，走分片上传路径
                if (!res.existFlag) {
                    client = new OSS({
                        region: "oss-cn-hangzhou",
                        accessKeyId: res.credentials.accessKeyId,
                        accessKeySecret: res.credentials.accessKeySecret,
                        stsToken: res.credentials.securityToken,
                        bucket: 'annotate-platform'
                    })
                    const name = `scrapSteelZipData/${file.name}`;
                    const partSize = 10 * 1024 * 1024;
                    const parallel = 3;
                    const options = {
                        // 获取分片上传进度、断点和返回值。
                        progress: async (p, cpt, res) => {
                            updateFileProgress(p, file);
                            // 进度为1时为上传完成，调saveFileName保存文件名，减少后续重复上传工作量
                            if (p === 1) {
                                await saveFileName(file, md5);
                                getFileList(md5, file);
                            }
                        },
                        parallel,
                        partSize,
                    }
                    // 分片上传。
                    await client.multipartUpload(name, file, {
                        ...options,
                    });
                } else {
                    updateFileProgress(1, file);
                    getFileList(md5, file);

                }
            })
        } else {
            //单文件上传
            uploadSingleImage(file);
        }
    }

    async function loopFetchFileList(currentClient, prefix): Promise<any> {
        return new Promise((resolve, reject) => {
            setTimeout(async () => {
                const result = await currentClient.list({
                    prefix,
                    // delimiter: '/'
                });
                if (!result.objects.length) {
                    loopFetchFileList(currentClient, prefix);
                } else {
                    resolve(result);
                }
            }, 20);
        })
    }

    async function getFileList(md5: string, file): Promise<any> {
        const res = await getFileAddress({
            fileMd5: md5,
        })
        client = new OSS({
            accessKeyId: res.credentials.accessKeyId,
            accessKeySecret: res.credentials.accessKeySecret,
            stsToken: res.credentials.securityToken,
            bucket: 'annotate-platform'
        })
        loopFetchFileList(client, res.fileDire).then(result => {
            addImages(result.objects, file);
            const getSubDirFiles = (data, currentClient) => {
                if (data && data.prefixes && data.prefixes.length) {
                    data.prefixes.forEach(async (v) => {
                        const r = await currentClient.list({
                            prefix: v,
                            delimiter: '/'
                        });
                        addImages(r.objects, file);
                        if (r && r.prefixes && r.prefixes.length) {
                            getSubDirFiles(r, currentClient);
                        }
                    })
                }
            }
            getSubDirFiles(result, client);
        })

    }

    async function confirmImport(): Promise<void> {
        await importImages({
            imageList: imgList.map((v) => {
                return {
                    imageName: v.folderName,
                    imageUrl: v.src
                }
            })
        });
        onAddNewData();
        setImportSuccess(true);
    }

    function updateFileProgress(p: number, file): void {
        const arr = [...progressRef.current];
        const index = arr.findIndex(v => v.uid === file.uid);
        arr[index > -1 ? index : 0] = { fileName: file.name, progress: p, uid: file.uid };
        setFilesProgress(arr);
    }

    async function uploadSingleImage(file: File): Promise<void> {
        const res = await uploadSingleFile({
        });
        const client = new OSS({
            accessKeyId: res.credentials.accessKeyId,
            accessKeySecret: res.credentials.accessKeySecret,
            stsToken: res.credentials.securityToken,
            bucket: 'annotate-platform'
        })
        const name = `scrapSteelDirectUpload/${file.name}`;
        const r = await client.put(name, file);
        updateFileProgress(1, file);
        const list = [...imgList, { name: file.name, src: r.url, isChecked: true, uid: nanoid(), folderName: getFolderName(file.name) }]
        const selectedNum = list.filter(v => v.isChecked).length;
        setImgList(val => [...val, { name: file.name, src: r.url, isChecked: true, uid: nanoid(), folderName: getFolderName(file.name), }]);
        setSelectedAll(list.every(v => v.isChecked));
        setSelectedCount(selectedNum);
        setIndeterminate(!!(selectedNum > 0 && selectedNum < list.length));
    }
    const uploadProps: UploadProps = {
        name: 'file',
        multiple: true,
        showUploadList: false,
        accept: '.zip,.jpg,.png,.jpeg,.bmp',
        beforeUpload: async (file) => {
            handleUploadFile(file)
            return false;
        },
    };

    function initUpload(): void {
        setFileList([]);
        setImgList([]);
        setImportSuccess(false);
        setFilesProgress([]);
        setSelectedCount(0);
        setSelectedAll(false);
    }

    return (
        <>{importSuccess ?
            <div>
                <Result
                    status="success"
                    title="导入数据成功"
                    subTitle={'成功导入' + selectedCount + '条数据'}
                    extra={[
                        <Button key="continue" onClick={initUpload}>
                            继续导入
                        </Button>,
                        <Button type="primary" key="finish" onClick={closeDrawer}>完成</Button>,
                    ]}
                />
            </div>
            :
            <div className='flex flex-col h-100%'>
                <div className='w-400px h-224px p-24px pb-10px'>
                    <Dragger {...uploadProps}>
                        <p className='ant-upload-drag-icon'>
                            <PlusOutlined style={{ fontSize: '14px' }} />
                        </p>
                        <p className='ant-upload-text'>点击或拖拽文件到此处上传</p>
                        <p className='ant-upload-hint'>
                            图片仅支持 png/jpg/jpeg/bmp, 单次限制最多 100 张图片，
                            <br />
                            压缩包源文件限制 5G 以内
                        </p>
                    </Dragger>

                </div>
                <div className='flex flex-col gap-5px' style={{ maxHeight: '132px', width: '400px', overflow: 'auto', padding: '0 24px 0' }}>
                    {fileList.length > 0 && filesProgress.map((v, i) => {
                        return (
                            <div key={v.uid} className='flex flex-justify-between flex-items-center bg-[#F7F8FA] gap-1 p-2'>
                                <span>
                                    <PaperClipOutlined className='mr-2' />
                                    {v.fileName}
                                </span>
                                {
                                    v.progress < 1 ?
                                        (
                                            <div>
                                                <span className='mr-2'>已上传{v.progress * 100}%</span>
                                                <Progress
                                                    type="circle"
                                                    trailColor="#e6f4ff"
                                                    percent={v.progress * 100}
                                                    strokeWidth={20}
                                                    size={14}
                                                    format={(number) => `上传中，已完成${number}%`}
                                                />
                                            </div>)
                                        : <CheckCircleOutlined style={{ color: '#00B42A' }} />
                                }

                            </div>
                        );
                    })}
                </div>
                <div className='flex flex-col overflow-hidden' style={{ flex: 1, padding: '0 24px 0' }}>
                    {!!imgList.length && <div className='flex flex-justify-between pt-10px pb-10px'>
                        <div>
                            <span className='font-500 text-16px color-#000 '>解析结果</span>&nbsp;&nbsp;&nbsp;&nbsp;
                            <span className='font-400 color-[#000]/60'>共<span className='font-500 color-#000 text-16px m-4px'>{imgList.length}</span>条数据</span>&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;
                            {/* <span className='font-400 color-[#000]/60'>解析成功<span className='font-500 color-#000 text-16px m-4px'>{imgList.length}</span>条</span>&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;
                            <span className='font-400 color-#F53F3F'>失败<span className='font-500 color-#F53F3F text-16px m-4px'>{0}</span>条</span> */}
                        </div>
                        <div>
                            <Checkbox
                                indeterminate={indeterminate}
                                checked={selectedAll}
                                onChange={(e) => {
                                    imgList.forEach(v => v.isChecked = e.target.checked);
                                    setSelectedAll(e.target.checked);
                                    setSelectedCount(e.target.checked ? imgList.length : 0);
                                    setIndeterminate(false);
                                }}>
                                已选{selectedCount}项</Checkbox>
                        </div>
                    </div>}
                    <div className='flex flex-wrap gap-10px' style={{ flex: 1, overflow: 'auto', width: '100%' }}>
                        {imgList.map((v, i) => {
                            return (
                                <div key={v.src + i} className='flex flex-col flex-items-center gap-10px'>
                                    <div className='position-relative h-141px w-141px overflow-hidden'>
                                        <Image
                                            width={141}
                                            height={141}
                                            src={v.src}
                                        />
                                        <Checkbox
                                            checked={v.isChecked}
                                            style={{ position: 'absolute', top: '5px', right: '5px' }}
                                            onChange={(e) => {
                                                const arr = imgList.map(item => {
                                                    if (item.uid === v.uid) {
                                                        item.isChecked = e.target.checked;
                                                    }
                                                    return item;
                                                })
                                                const selected = arr.filter(v => v.isChecked).length;
                                                setImgList(arr);
                                                setSelectedAll(arr.every(v => v.isChecked));
                                                setSelectedCount(selected);
                                                setIndeterminate(!!(selected > 0 && selected < arr.length));
                                            }} />
                                    </div>
                                    <span className='block w-141px text-center break-all'>{v.name}</span>
                                </div>
                            );
                        })}
                    </div>
                </div>
                <div className='flex flex-justify-end gap-10px p-24px border-t-1 border-t-#E5E6EB'>
                    <Button onClick={closeDrawer}>取消</Button>
                    <Button type="primary" onClick={confirmImport}>确认导入</Button>
                </div>
            </div>
        }

        </>
    );
}

export default React.memo(BatchUploadComponent);
